import sys,time,re

def readVhdlFile(filePath):
    # 输出基本格式
    vhdl = {
        'library': None,
        'use': [],
        'entity': {
            'name':None,
            'inport':[],
            'outport':[]
        }
    }
    # 字符串清空操作
    clr = lambda str: str.replace(' ','').replace('\n','').replace('\t','')
    # 块级读入操作
    def readABlock(fline,f,end):
        while True:
            temp = f.readline()
            temp = temp.lower()
            temp = temp.strip()
            fline += temp
            if end==';' and temp.endswith(';'):
                break
            if end=='end' and "end" in temp:
                break
        return fline
    # 读操作
    with open(filePath,"r") as f:
        while True:
            block = f.readline()
            if not block:
                break
            block = block.lower()
            block = block.strip()
            if block.startswith('library'):
                if block.endswith(';'):
                    pass
                else:
                    block = readABlock(block,f,';')
                block = clr(block)
                vhdl['library']=block.replace('library','').replace(';','')
            elif block.startswith('use'): 
                if block.endswith(';'):
                    pass
                else:
                    block = readABlock(block,f,';')
                block = clr(block)
                vhdl['use'].append(block.replace('use','').replace(';',''))
            elif block.startswith('entity'):
                if "end" in block:
                    pass
                else:
                    block = readABlock(block,f,'end')
                block = clr(block)
                # entity name & ports
                res = re.match(".*entity(.*)isport\((.*)\).*",block)
                ## name
                vhdl['entity']['name'] = res.groups(1)[0]
                ## ports
                ports = res.groups(1)[1].split(';')
                for port in ports:
                    pt = []
                    ts = port.split(":")
                    names = ts[0].split(',')
                    type = ""
                    if "vector" in ts[1]:
                        type = "vector"
                    else:
                        type = "bit"
                    dir = re.match("(.*)std.*",ts[1]).groups(1)[0]
                    trange = []
                    if type == "vector":
                        trange = re.match(".*\((.*)\).*",ts[1]).groups(1)[0]
                        if "downto" in trange:
                            trange = " downto ".join(trange.split("downto"))
                        else:
                            trange = " to ".join(trange.split("to"))
                        for name in names:
                            pt.append({'name': name,'type': type,'range': trange})
                    else:
                        for name in names:
                            pt.append({'name': name,'type': type})
                    vhdl['entity'][dir+'port']+=pt
    return vhdl

vhdl = readVhdlFile(sys.argv[1])

inports = vhdl['entity']['inport']
inportlines = []
for inport in inports:
    arr = []
    if inport['type']=="vector":
        if " downto " in inport['range']:
            trange = range(int(inport['range'].split(" downto ")[0]),int(inport['range'].split(" downto ")[1])-1,-1)
        else:
            trange = range(int(inport['range'].split(" to ")[0]),int(inport['range'].split(" to ")[1])+1,1)
        while True:
            arr.clear()
            for i, b in enumerate(trange):
                line = input(inport['name']+"(%d): " % b)
                if i==0:
                    for j in line:
                        arr.append("")
                for j, c in enumerate(line):
                    arr[j]=arr[j]+'0' if c=='_' else arr[j]+'1'
            if False in list(map(lambda x: len(x)==len(arr[0]),arr)):
                print("Please input the vector signal with all bits are same length；")
            else:
                break
    else:
        line = input(inport['name']+": ")
        arr.clear()
        for c in line:
            arr.append(0) if c=='_' else arr.append(1)
    inportlines.append(arr)

with open('_tb.'.join(sys.argv[1].split('.')),"w") as f:
    f.write("library "+vhdl["library"]+";\n")
    for use in vhdl["use"]:
        f.write("use "+use+";\n\n")
    f.write("entity "+vhdl["entity"]["name"]+"_tb is\n")
    f.write("end "+vhdl["entity"]["name"]+"_tb;\n\n")
    f.write("architecture rtl of "+vhdl["entity"]["name"]+"_tb is\n")
    f.write("\tcomponent "+vhdl["entity"]["name"]+"\n")
    f.write("\t\tport(\n")
    ports = []
    for port in vhdl['entity']['inport']:
        ports.append("\t\t\t"+port['name']+": in "+("std_logic" if port['type']=="bit" else "std_logic_vector("+port['range']+")"))
    for port in vhdl['entity']['outport']:
        ports.append("\t\t\t"+port['name']+": out "+("std_logic" if port['type']=="bit" else "std_logic_vector("+port['range']+")"))
    f.write(";\n".join(ports))
    f.write("\n\t\t);\n")
    f.write("\tend component;\n")
    for port in vhdl['entity']['inport']:
        f.write("\tsignal "+port['name']+": "+("std_logic;\n" if port['type']=="bit" else "std_logic_vector("+port['range']+");\n"))
    for port in vhdl['entity']['outport']:
        f.write("\tsignal "+port['name']+": "+("std_logic;\n" if port['type']=="bit" else "std_logic_vector("+port['range']+");\n"))
    f.write("begin\n")
    f.write("\tu1: "+vhdl["entity"]["name"]+" port map("+",".join(list(map(lambda x:x['name'],vhdl['entity']['inport'])))+","+",".join(list(map(lambda x:x['name'],vhdl['entity']['outport'])))+");\n")
    a = len(inportlines)
    for i in range(a):
        inportline = inportlines[i]
        f.write("\tprocess\n")
        f.write("\tbegin\n")
        if vhdl['entity']['inport'][i]['type']=="vector":
            for inportpot in inportline:
                f.write("\t\t"+vhdl['entity']['inport'][i]['name']+"<=\""+inportpot+"\";wait for 20 ns;\n")
        else:
            for inportpot in inportline:
                f.write("\t\t"+vhdl['entity']['inport'][i]['name']+"<='"+str(inportpot)+"';wait for 20 ns;\n")
        f.write("\t\twait;\n")
        f.write("\tend process;\n")

    f.write("end rtl;\n")